package class24;

import java.util.LinkedList;

// 测试链接：https://leetcode.com/problems/gas-station
public class Code03_GasStation {

	// 这个方法的时间复杂度O(N)，额外空间复杂度O(N)
	public static int canCompleteCircuit(int[] gas, int[] cost) {
		boolean[] good = goodArray(gas, cost);
		for (int i = 0; i < gas.length; i++) {
			if (good[i]) {
				return i;
			}
		}
		return -1;
	}

	public static boolean[] goodArray(int[] g, int[] c) {
		int N = g.length;
		int M = N << 1;
		int[] arr = new int[M];
		for (int i = 0; i < N; i++) {
			arr[i] = g[i] - c[i];
			arr[i + N] = g[i] - c[i];
		}
		for (int i = 1; i < M; i++) {
			arr[i] += arr[i - 1];
		}
		// 举个例子说明一下
		// 比如纯能数组(也就是燃料 - 距离之后)的数组 :
		// 纯能数组 = 3, 2,-6, 2, 3,-4, 6
		// 数组下标 = 0  1  2  3  4  5  6
		// 客观上说:
		// 0位置不是良好出发点
		// 1位置不是良好出发点
		// 2位置不是良好出发点
		// 3位置是良好出发点
		// 4位置不是良好出发点
		// 5位置不是良好出发点
		// 6位置是良好出发点
		// 把数组增倍之后 : 
		// arr   = 3, 2,-6, 2, 3,-4, 6, 3, 2,-6, 2, 3,-4, 6
		// 然后计算前缀和 :
		// arr   = 3, 5,-1, 1, 4, 0, 6, 9,11, 5, 7,10, 6,12
		// index = 0  1  2  3  4  5  6  7  8  9 10 11 12 13
		// 这些就是上面发生的过程
		// 接下来生成长度为N的窗口
		LinkedList<Integer> w = new LinkedList<>();
		for (int i = 0; i < N; i++) {
			while (!w.isEmpty() && arr[w.peekLast()] >= arr[i]) {
				w.pollLast();
			}
			w.addLast(i);
		}
		// 上面的过程，就是先遍历N个数，然后建立窗口
		// arr   =[3, 5,-1, 1, 4, 0, 6],9,11, 5, 7,10, 6,12
		// index = 0  1  2  3  4  5  6  7  8  9 10 11 12 13
		// w中的内容如下:
		// index:  2 5 6
		// value: -1 0 6
		// 左边是头，右边是尾，从左到右严格变大
		// 此时代表最原始的arr的这部分的数字: 
		// 原始的值 = [3, 2,-6, 2, 3,-4, 6],3, 2,-6, 2, 3,-4, 6
		// 原始下标 =  0  1  2  3  4  5  6  0  1  2  3  4  5  6
		// 上面这个窗口中，累加和最薄弱的点，就是w中最左信息
		// 也就是会累加出，-1这个值，所以会走不下去。
		// 宣告了此时0位置不是良好出发点。
		// 接下来的代码，就是依次考察每个点是不是良好出发点。
		// 目前的信息是:
		// 计算的前缀和 :
		// arr   =[3, 5,-1, 1, 4, 0, 6],9,11, 5, 7,10, 6,12
		// index = 0  1  2  3  4  5  6  7  8  9 10 11 12 13
		// w中的内容如下:
		// index:  2 5 6
		// value: -1 0 6
		// 此时代表最原始的arr的这部分的数字: 
		// 原始的值 = [3, 2,-6, 2, 3,-4, 6],3, 2,-6, 2, 3,-4, 6
		// 原始下标 =  0  1  2  3  4  5  6  0  1  2  3  4  5  6
		// 现在让窗口往下移动
		// 计算的前缀和 :
		// arr   = 3,[5,-1, 1, 4, 0, 6, 9],11, 5, 7,10, 6,12
		// index = 0  1  2  3  4  5  6  7   8  9 10 11 12 13
		// w中的内容如下:
		// index:  2 5 6 7
		// value: -1 0 6 9
		// 此时代表最原始的arr的这部分的数字: 
		// 原始的值 =  3,[2,-6, 2, 3,-4, 6, 3],2,-6, 2, 3,-4, 6
		// 原始下标 =  0  1  2  3  4  5  6  0  1  2  3  4  5  6
		// 上面这个窗口中，累加和最薄弱的点，就是w中最左信息
		// 但是w最左的值是-1啊！而这个窗口中最薄弱的累加和是-4啊。
		// 对！所以最薄弱信息 = 窗口中的最左信息 - 窗口左侧刚出去的数(代码中的offset!)
		// 所以，最薄弱信息 = -1 - 0位置的3(窗口左侧刚出去的数) = -4
		// 看到了吗？最薄弱信息，依靠这种方式，加工出来了！
		// 宣告了此时1位置不是良好出发点。
		// 我们继续，让窗口往下移动
		// 计算的前缀和 :
		// arr   = 3, 5,[-1, 1, 4, 0, 6, 9,11], 5, 7,10, 6,12
		// index = 0  1   2  3  4  5  6  7  8   9 10 11 12 13
		// w中的内容如下:
		// index:  2  5  6  7  8
		// value: -1  0  6  9 11
		// 此时代表最原始的arr的这部分的数字: 
		// 原始的值 =  3, 2,[-6, 2, 3,-4, 6, 3, 2],-6, 2, 3,-4, 6
		// 原始下标 =  0  1   2  3  4  5  6  0  1   2  3  4  5  6
		// 上面这个窗口中，累加和最薄弱的点，就是w中最左信息
		// 但是w最左的值是-1啊！而这个窗口中最薄弱的累加和是-6啊。
		// 对！所以最薄弱信息 = 窗口中的最左信息 - 窗口左侧刚出去的数(代码中的offset!)
		// 所以，最薄弱信息 = -1 - 1位置的5(窗口左侧刚出去的数) = -6
		// 看到了吗？最薄弱信息，依靠这种方式，加工出来了！
		// 宣告了此时2位置不是良好出发点。
		// 我们继续，让窗口往下移动
		// 计算的前缀和 :
		// arr   = 3, 5, -1,[1, 4, 0, 6, 9,11, 5], 7,10, 6,12
		// index = 0  1   2  3  4  5  6  7  8  9  10 11 12 13
		// w中的内容如下:
		// index:  5  9
		// value:  0  5
		// 没错，9位置的5进来，让6、7、8位置从w的尾部弹出了，
		// 同时原来在w中的2位置已经过期了，所以也弹出了，因为窗口左边界已经划过2位置了
		// 此时代表最原始的arr的这部分的数字: 
		// 原始的值 =  3, 2, -6,[2, 3,-4, 6, 3, 2, -6],2, 3,-4, 6
		// 原始下标 =  0  1   2  3  4  5  6  0  1   2  3  4  5  6
		// 上面这个窗口中，累加和最薄弱的点，就是w中最左信息
		// 但是w最左的值是0啊！而这个窗口中最薄弱的累加和是1啊
		// 对！所以最薄弱信息 = 窗口中的最左信息 - 窗口左侧刚出去的数(代码中的offset!)
		// 所以，最薄弱信息 = 0 - 2位置的-1(窗口左侧刚出去的数) = 1
		// 看到了吗？最薄弱信息，依靠这种方式，加工出来了！
		// 宣告了此时3位置是良好出发点。
		// 往下同理
		boolean[] ans = new boolean[N];
		for (int offset = 0, i = 0, j = N; j < M; offset = arr[i++], j++) {
			if (arr[w.peekFirst()] - offset >= 0) {
				ans[i] = true;
			}
			if (w.peekFirst() == i) {
				w.pollFirst();
			}
			while (!w.isEmpty() && arr[w.peekLast()] >= arr[j]) {
				w.pollLast();
			}
			w.addLast(j);
		}
		return ans;
	}

}
